Форум dkLab и Denwer
Здесь общаются Web-разработчики.
Генеральный спонсор:
Хостинг «Джино»

Парсер SQL-запроса (balakin)
Author Message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Wed Aug 03, 2005 10:53 am (написано за 8 минут 43 секунды)
   Post subject: Парсер SQL-запроса
Reply with quote

Уже неделю бьюсь, я наверно с ума сойду от этих регэкспов.
Имеется запрос типа:
Code (SQL): скопировать код в буфер обмена
SELECT * FROM table1 WHERE id1=2, id2=4 ORDER BY id2
Необходимо вытащить все параметры (как работают сами БД? Они же как-то парсят).
Было бы легко, если все параметры были обязательными, но ни WHERE, ни ORDER может не быть в запросе.

Единственное, что более менее сейчас получается, то вот это
Code (php): скопировать код в буфер обмена
preg_match (www.php.net/preg_match)('/^select\s(.+)\sfrom\s([^\s]+)(?:\s((?:where|order|group)\s.+))?/i', $sql, $regs);
но мне не нравится часть "from\s([^\s]+)", т.к. таблица может быть и не одна (например ... FROM table1, table2 ...), а сделать "from\s(.+)" нельзя, т.к., почему-то, не срабатывает идущая следом часть со знаком вопроса на конце (ПОЧЕМУ? ведь условие выполняется).

ps: может есть ссылки? я что-то не нашел в инете (не то, видимо, искал).
Back to top
View user's profile Send private message
MVH
Участник форума



Joined: 01 May 2003
Posts: 261
Карма: 2
   поощрить/наказать


PostPosted: Wed Aug 03, 2005 1:12 pm (спустя 2 часа 19 минут; написано за 1 минуту 23 секунды)
   Post subject:
Reply with quote

balakin
Я немного не понял, в каком виде и какие параметры Вам нужны.
Необходимо, что бы из Вашего sql запроса можно было выдрать это:
Code (any language): скопировать код в буфер обмена
*
table1
id1=2, id2=4
id2
Так что ли?
Back to top
View user's profile Send private message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Wed Aug 03, 2005 1:14 pm (спустя 2 минуты; написано за 20 секунд)
   Post subject:
Reply with quote

Именно так.
Back to top
View user's profile Send private message
MVH
Участник форума



Joined: 01 May 2003
Posts: 261
Карма: 2
   поощрить/наказать


PostPosted: Wed Aug 03, 2005 4:37 pm (спустя 3 часа 23 минуты; написано за 2 минуты 40 секунд)
   Post subject:
Reply with quote

Попробуйте, например, так:
Code (php): скопировать код в буфер обмена
preg_match (www.php.net/preg_match)("/^SELECT (.+?) FROM (.+?)(?: WHERE (.+?))?(?: ORDER BY (.+?))?$/i", $sql, $regs);
Ваш sql запрос вроде нормально парсится (с учётом убирания секции WHERE или ORDER BY).
Протестите его немного и если всё нормально - то таким же образом:
Code (SQL): скопировать код в буфер обмена
(?: ORDER BY (.+?))?
добавьте и другие секции: GROUP, JOIN и т.д.
Back to top
View user's profile Send private message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Wed Aug 03, 2005 6:06 pm (спустя 1 час 28 минут; написано за 3 минуты 40 секунд)
   Post subject:
Reply with quote

класс, спасибо. значит я еще фигово регэкспы знаю.
а зачем знак вопроса в выражении FROM (.+?) (и вообще во всех (.+?))
я без него делал, и, естественно, не работало - какая-то тут тонкость.

ps: вот, сейчас все же еле нашел рекомендуюмую книжку по регэкспам (заодно и по PHP5), буду изучать...
Back to top
View user's profile Send private message
Eugene Babushkin
Участник форума



Joined: 01 Aug 2003
Posts: 263
Карма: 4
   поощрить/наказать

Location: 59, Russia

PostPosted: Wed Aug 03, 2005 6:59 pm (спустя 53 минуты; написано за 3 минуты 34 секунды)
   Post subject:
Reply with quote

balakin wrote:
регэкспы
Мне кажется, регулярные выражения звучит гораздо лучше (-;
balakin wrote:
зачем знак вопроса
В выражении
balakin wrote:
(.+?)
знак вопроса (?) заставляет + "умерить аппетит" (жадный квантификатор) и совпасть не с максимальным, а с минимальным возможным числом символов.

Совет: Купите книгу dk. Тема регулярных выражения в ней очень доходчиво изложена, как и другие темы...
Back to top
View user's profile Send private message
MVH
Участник форума



Joined: 01 May 2003
Posts: 261
Карма: 2
   поощрить/наказать


PostPosted: Wed Aug 03, 2005 7:22 pm (спустя 22 минуты; написано за 1 минуту 5 секунд)
   Post subject:
Reply with quote

balakin wrote:
вот, сейчас все же еле нашел рекомендуюмую книжку по регэкспам (заодно и по PHP5), буду изучать...
На сайте php.net подробно описан синтаксис регулярных выражений (на русском):
ru3.php.net/manual/ru/reference.pcre.pattern.modifiers.php
ru3.php.net/manual/ru/reference.pcre.pattern.syntax.php
Back to top
View user's profile Send private message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Thu Aug 04, 2005 8:31 am (спустя 13 часов 8 минут; написано за 12 минут 13 секунд)
   Post subject:
Reply with quote

Eugene Babushkin wrote:
Купите книгу dk. Тема регулярных выражения в ней очень доходчиво изложена, как и другие темы...
Как раз ее и купил... раритетом уже становится.

MVH
По тем ссылкам я искал... но кто же знал (вернее надо было знать), что надо '?' искать, да еще в таком контексте... просто в тех ссылках это так невзначай описано, что пропустить легче легкого. Надо бы выделять такие вещи, т.к. это исключение из правила.

Хотя, вообще, конечно нелогично сделано это правило. По логике, выражение без знака вопроса жадности "...FROM (.+)(?: WHERE (.+?))?..." обязано выполняться, т.к. WHERE все же присутствует... но... раз "надо, так надо" ;)
"Озвучиваю" это правило на человечий: "Если стоит (.+), то я плюю на все ограничения со знаком ? после его. Зачем вы их писали!?" :D

Еще раз, спасибо.

зы: почти тоже самое придумал, только здесь даже порядок следования не важен. После достаточно "пробежаться" по полученному массиву и вытащить все данные.
Code (php): скопировать код в буфер обмена
$regs = preg_split (www.php.net/preg_split)('/[\s]*(SELECT|FROM|WHERE|ORDER\s+BY|GROUP\s+BY)[\s]*/i', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);
Back to top
View user's profile Send private message
MVH
Участник форума



Joined: 01 May 2003
Posts: 261
Карма: 2
   поощрить/наказать


PostPosted: Thu Aug 04, 2005 10:32 am (спустя 2 часа 55 секунд; написано за 3 минуты 40 секунд)
   Post subject:
Reply with quote

balakin wrote:
зы: почти тоже самое придумал, только здесь даже порядок следования не важен. После достаточно "пробежаться" по полученному массиву и вытащить все данные.
Code (php): скопировать код в буфер обмена
$regs = preg_split (www.php.net/preg_split)('/[\s]*(SELECT|FROM|WHERE|ORDER\s+BY|GROUP\s+BY)[\s]*/i', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);
Одно замечание. Попробуйте пропарсить этим выражением этот sql код:
Code (SQL): скопировать код в буфер обмена
SELECT `qwe`, `select` FROM table1 WHERE qw=2, 1=1
Не забывайте, что поле или таблица может называться `select`, `from` и т.д.
Поставьте в шаблоне выражения, например, пробел после SELECT и т.д.
Т.е. вот так:
Code (php): скопировать код в буфер обмена
$regs = preg_split (www.php.net/preg_split)('/[\s]*(SELECT |FROM |WHERE |ORDER\s+BY |GROUP\s+BY )[\s]*/i', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);
Back to top
View user's profile Send private message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Thu Aug 04, 2005 10:43 am (спустя 11 минут; написано за 4 минуты 7 секунд)
   Post subject:
Reply with quote

Кстати, тогда уж наверное лучше вот так (+ вместо * в конце выражения)
Code (SQL): скопировать код в буфер обмена
$regs = preg_split('/[\s]*(SELECT|FROM|WHERE|ORDER\s+BY|GROUP\s+BY)[\s]+/i', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);
Я уже об этом подумал, и... решил preg_split вообще не использовать.
"Пробел после SELECT" тоже не пойдет, т.к. может быть так
Code (SQL): скопировать код в буфер обмена
SELECT `qwe`, id_select FROM table1 WHERE qw=2, 1=1
можно бы еще ДО ограничивать, но до "нужного" SELECT же ничего нет. Как это сделать, не знаю.
Back to top
View user's profile Send private message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Thu Aug 04, 2005 10:51 am (спустя 8 минут; написано за 44 секунды)
   Post subject:
Reply with quote

Всё, разобрался. Вот теперь rtfm помог.
Code (php): скопировать код в буфер обмена
$regs = preg_split (www.php.net/preg_split)('/[\s]*\b(SELECT|FROM|WHERE|ORDER\s+BY|GROUP\s+BY)[\s]+/i', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);
Back to top
View user's profile Send private message
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Thu Aug 04, 2005 3:14 pm (спустя 4 часа 22 минуты; написано за 2 минуты 28 секунд)
   Post subject:
Reply with quote

Сделал простенький класс (там, конечно, параметры немного неверно разделяются ф-цией splitbycomma(), но все же)... может кому и пригодится.
Плюс не сделаны сами ф-ции по добавлению дополнительных параметров, но это уже дело наживное.

ps: чуть поправил файл.


class.SQLParser.zip
 Description:

Download
 Filename:  class.SQLParser.zip
 Filesize:  1.98 KB
 Downloaded:  779 Time(s)

Back to top
View user's profile Send private message
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 412
   поощрить/наказать


PostPosted: Thu Aug 04, 2005 4:46 pm (спустя 1 час 32 минуты; написано за 39 секунд)
   Post subject:
Reply with quote

Класс довольно серьезного парсинга SQL-запросов есть в составе phpMyAdmin. Можете поискать там в исходниках, он довольно мощный.
balakin wrote:
SELECT * FROM table1 WHERE id1=2, id2=4 ORDER BY id2
Может, SELECT * FROM table1 WHERE id1=2 AND id2=4 ORDER BY id2 ?
Back to top
View user's profile Send private message Send e-mail
balakin
Заглянувший



Joined: 03 Aug 2005
Posts: 13
Карма: -1
   поощрить/наказать


PostPosted: Fri Aug 05, 2005 8:48 am (спустя 16 часов 2 минуты; написано за 2 минуты 4 секунды)
   Post subject:
Reply with quote

Вы правы... поставил исключение.
Глянул мельком phpMyAdmin - такой функциональности мне не надо (в Интербейзе у нас все запросы сводятся к вызову одной хранилки), чтобы разбираться в ней.
Back to top
View user's profile Send private message
Кухан
Guest





Карма: 388
   поощрить/наказать


PostPosted: Sun Oct 30, 2005 11:46 am (спустя 2 месяца 25 дней 2 часа 57 минут; написано за 3 минуты 9 секунд)
   Post subject:
Reply with quote

А не существует ли кого-нибудь парсера SQL, который бы автоматически добавлял префиксы к именам таблиц в запросах?
Может у кого-нибудь есть готовый скрипт? А то разбираться в устройстве такого монстра как парсер PHPMyAdmin тяжело.

P.S. извиняюсь если не туда написал.
Back to top
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 412
   поощрить/наказать


PostPosted: Sun Oct 30, 2005 3:47 pm (спустя 4 часа 23 секунды; написано за 1 минуту 6 секунд)
   Post subject:
Reply with quote

А в phpMyAdmin вряд ли прямо все имена таблиц выделяются, так что, скорее всего, даже он Вам не поможет. Да это и из пушки по воробьям. Учитывая, что запросы могут быть очень сложными, я думаю, эта задача вообще практически неразрешима. Вернее, надо быть SQL-сервером, чтобы ее решить.
Back to top
View user's profile Send private message Send e-mail
Кухан
Guest





Карма: 388
   поощрить/наказать


PostPosted: Sun Oct 30, 2005 4:21 pm (спустя 34 минуты; написано за 3 минуты 12 секунд)
   Post subject:
Reply with quote

Да, конечно, запросы могут быть сложными, но мне достаточно чтобы префикс добавлялся хотя бы в распространеных запросах, типа SELECT, INSERT, DELETE и запросы только к MySQL (другие СУБД не нужны). И в большинстве запросов имена таблиц идут после ключевых слов типа: FROM, INTO.
Back to top
Дмитрий Котеров
Администратор



Joined: 10 Mar 2003
Posts: 13665
Карма: 412
   поощрить/наказать


PostPosted: Sun Oct 30, 2005 5:31 pm (спустя 1 час 9 минут)
   Post subject:
Reply with quote


М

Перенесено из форума: Разное :: PHP.
Перенесено в форум: SQL и PHP :: SQL.
Back to top
View user's profile Send private message Send e-mail
Kir
Заглянувший



Joined: 09 Aug 2003
Posts: 3
Карма: 0
   поощрить/наказать

Location: Москва

PostPosted: Thu Oct 25, 2007 3:11 pm (спустя 1 год 11 месяцев 25 дней 21 час 40 минут; написано за 3 минуты 29 секунд)
   Post subject:
Reply with quote

balakin wrote:
Всё, разобрался. Вот теперь rtfm помог.
Code (php): скопировать код в буфер обмена
$regs = preg_split (www.php.net/preg_split)('/[\s]*\b(SELECT|FROM|WHERE|ORDER\s+BY|GROUP\s+BY)[\s]+/i', $sql, -1, PREG_SPLIT_DELIM_CAPTURE);
Тема старая, но все еще актуальная. Распарсится ли такой запрос:
Code (SQL): скопировать код в буфер обмена
SELECT * FROM db_message WHERE text='Where do you go today? Can you select the bar?'
Back to top
View user's profile Send private message
Display posts from previous:   
Post new topic   Reply to topic All times are GMT + 3 Hours
Page 1 of 1    Email to a Friend.
You cannot post new topics in this forum. You cannot reply to topics in this forum. You cannot edit your posts in this forum. You cannot delete your posts in this forum. You cannot vote in polls in this forum. You cannot attach files in this forum. You can download files in this forum.
XML